/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

/*
 * JCalendarPanel.java
 *
 * Created on 2009-12-4, 11:24:11
 */
package cn.ekuma.epos.ical;

import cn.ekuma.epos.datalogic.I_DataLogicCustomers;
import cn.ekuma.epos.datalogic.I_DataLogicERP;
import cn.ekuma.epos.datalogic.I_DataLogicSales;
import cn.ekuma.epos.datalogic.I_DataLogicSystem;
import cn.ekuma.epos.ical.repository.OrderEventStore;
import cn.ekuma.epos.ical.repository.OrderLineEventStore;
import cn.ekuma.epos.module.ERP_UI_Swing_Model;
import cn.ekuma.epos.qkorder.dialog.JOrderFilterQBFDialog;
import cn.ekuma.rabbit.spi.I_ModelPart;

import com.openbravo.data.basic.BasicException;
import com.openbravo.data.gui.MessageInf;
import com.openbravo.pos.base.AppLocal;
import com.openbravo.pos.base.AppView;
import com.openbravo.pos.base.BeanFactoryApp;
import com.openbravo.pos.base.BeanFactoryException;
import com.openbravo.pos.base.I_AppView;
import com.openbravo.pos.forms.JPanelView;
import com.openbravo.pos.panels.JOrderLineFilterDialog;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Container;
import java.awt.FlowLayout;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.net.URL;
import java.util.Collections;
import java.util.HashMap;
import java.util.Vector;
import javax.swing.BorderFactory;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JDialog;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextField;
import javax.swing.SwingUtilities;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import us.k5n.ical.BogusDataException;
import us.k5n.ical.Constants;
import us.k5n.ical.Date;
import us.k5n.ical.Event;
import us.k5n.ical.ICalendarParser;
import us.k5n.k5ncal.AppPreferences;
import us.k5n.k5ncal.CalendarRefresher;
import us.k5n.k5ncal.ColorButton;
import us.k5n.k5ncal.EditEventWindow;
import us.k5n.k5ncal.EditRemoteCalendarWindow;
import us.k5n.k5ncal.EventViewPanel;
import us.k5n.k5ncal.JListWithCheckBoxes;
import us.k5n.k5ncal.ListItem;
import us.k5n.k5ncal.ListItemChangeListener;
import us.k5n.k5ncal.ListItemMenuItem;
import us.k5n.k5ncal.MyCalendarPanel;
import us.k5n.k5ncal.MyScrollPane;
import us.k5n.k5ncal.ProportionalLayout;
import us.k5n.k5ncal.RemoteCalendarUpdater;
import us.k5n.k5ncal.SwingWorker;
import us.k5n.k5ncal.data.Calendar;
import us.k5n.k5ncal.data.HttpClient;
import us.k5n.k5ncal.data.HttpClientStatus;
import us.k5n.k5ncal.data.RepositoryChangeListener;
import us.k5n.k5ncal.data.SingleEvent;
import us.k5n.ui.AccordionPane;
import us.k5n.ui.calendar.CalendarLocal;
import us.k5n.ui.calendar.CalendarPanel;
import us.k5n.ui.calendar.CalendarPanelSelectionListener;
import us.k5n.ui.calendar.EventInstance;

/**
 *
 * @author Administrator
 */
public class JCalendarPanel extends javax.swing.JPanel implements JPanelView, BeanFactoryApp, Constants, RepositoryChangeListener,
        CalendarPanelSelectionListener, CalendarRefresher ,I_ModelPart<ERP_UI_Swing_Model>{

    public static final String CALENDARS_XML_FILE = "calendars.xml";
    public static final String DEFAULT_DIR_NAME = "k5nCal";
    EventViewPanel eventViewPanel;
    ERPRepository dataRepository;
    CalendarPanel calendarPanel;
    AccordionPane ap;
    JListWithCheckBoxes calendarJList, erpCalendarJList;
    JList categoryJList;
    String searchText = null;
    private static File lastExportDirectory = null;
    AppPreferences prefs;
    File dataDir = null;

    protected I_DataLogicSystem dlSystem;
    protected I_DataLogicERP dlSales;
    protected I_DataLogicCustomers dlCustomers;

    static final String MENU_CALENDAR_EDIT = CalendarLocal.getIntString("MENU_CALENDAR_EDIT");
    static final String MENU_CALENDAR_REFRESH = CalendarLocal.getIntString("MENU_CALENDAR_REFRESH");
    static final String MENU_CALENDAR_DELETE =  CalendarLocal.getIntString("MENU_CALENDAR_DELETE");
    static final String MENU_CALENDAR_ADD_EVENT =  CalendarLocal.getIntString("MENU_CALENDAR_ADD_EVENT");
    static final String MENU_CALENDAR_VIEW_ERRORS =  CalendarLocal.getIntString("MENU_CALENDAR_VIEW_ERRORS");
    static final String ADD_EVENT_LABEL =  CalendarLocal.getIntString("ADD_EVENT_LABEL");
    static final String EDIT_EVENT_LABEL =  CalendarLocal.getIntString("EDIT_EVENT_LABEL");
    static final String DELETE_EVENT_LABEL = CalendarLocal.getIntString("DELETE_EVENT_LABEL");
    static final String LARGER_FONT_LABEL =  CalendarLocal.getIntString("LARGER_FONT_LABEL");
    static final String SMALLER_FONT_LABEL =  CalendarLocal.getIntString("SMALLER_FONT_LABEL");
    private boolean fontsInitialized = false;
    JFrame parent;

    AppView m_App;
    
    /** Creates new form JCalendarPanel */
    public JCalendarPanel() {
    }

    public void init(I_AppView m_App) throws BeanFactoryException {
        initComponents();
        this.m_App=(AppView) m_App;
        parent = (JFrame) SwingUtilities.getWindowAncestor(this);
        prefs = AppPreferences.getInstance();

        // Load data
        File dataDir = getDataDirectory();
        dataRepository = new ERPRepository(dataDir, loadCalendars(dataDir), false);
        // Ask to be notified when the repository changes (user adds/edits
        // an entry)
        dataRepository.addChangeListener(this);

        ap = new AccordionPane();
        ap.addPanel( CalendarLocal.getIntString("Label.Calendar"), createCalendarSelectionPanel(dataRepository.getCalendars()));
        ap.addPanel(CalendarLocal.getIntString("Label.Categories"), createCategorySelectionPanel(dataRepository.getCategories()));
        ap.addPanel(CalendarLocal.getIntString("Label.ERPCalendar"), createERPCalendarSelectionPanel(dataRepository.getERPCalendars()));
        ap.setTooltipTextAt(0,  CalendarLocal.getIntString("Label.Calendar.TooltipText"));
        ap.setTooltipTextAt(1,  CalendarLocal.getIntString("Label.Categories.TooltipText"));
        ap.setTooltipTextAt(2,  CalendarLocal.getIntString("Label.ERPCalendar.TooltipText"));


        jCalendars.add(ap, BorderLayout.CENTER);

        eventViewPanel = new EventViewPanel();
        eventViewPanel.setBorder(BorderFactory.createTitledBorder(CalendarLocal.getIntString("Label.EventDetails")));
        jPanel3.add(eventViewPanel, BorderLayout.CENTER);

        calendarPanel = new MyCalendarPanel(dataRepository);
        calendarPanel.addSelectionListener(this);
        calendarPanel.setShowTime(prefs.getDisplayHourInMonthView());
        rightPanel.add(calendarPanel, BorderLayout.CENTER);

        updateToolbar();
        //this.setVisible ( true );

        // Start a thread to update the remote calendars as needed.
        RemoteCalendarUpdater updater = new RemoteCalendarUpdater(
                this.dataRepository, this);
        updater.start();
    }

    /** This method is called from within the constructor to
     * initialize the form.
     * WARNING: Do NOT modify this code. The content of this method is
     * always regenerated by the Form Editor.
     */
    @SuppressWarnings("unchecked")
    // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
    private void initComponents() {

        jSplitPane1 = new javax.swing.JSplitPane();
        jPanel1 = new javax.swing.JPanel();
        jSplitPane2 = new javax.swing.JSplitPane();
        jCalendars = new javax.swing.JPanel();
        jPanel3 = new javax.swing.JPanel();
        rightPanel = new javax.swing.JPanel();
        jToolbar = new javax.swing.JPanel();
        editButton = new javax.swing.JButton();
        deleteButton = new javax.swing.JButton();
        largerButton = new javax.swing.JButton();
        smallerButton = new javax.swing.JButton();
        jButton2 = new javax.swing.JButton();
        jOrderEvent = new javax.swing.JButton();
        jOrderLineEvent = new javax.swing.JButton();
        jMessagePanel = new javax.swing.JPanel();
        messageArea = new javax.swing.JLabel();

        setLayout(new java.awt.BorderLayout());

        jSplitPane1.setDividerLocation(160);

        jPanel1.setLayout(new java.awt.BorderLayout());

        jSplitPane2.setDividerLocation(300);
        jSplitPane2.setOrientation(javax.swing.JSplitPane.VERTICAL_SPLIT);

        jCalendars.setLayout(new java.awt.BorderLayout());
        jSplitPane2.setTopComponent(jCalendars);

        jPanel3.setPreferredSize(new java.awt.Dimension(0, 350));
        jPanel3.setLayout(new java.awt.BorderLayout());
        jSplitPane2.setBottomComponent(jPanel3);

        jPanel1.add(jSplitPane2, java.awt.BorderLayout.CENTER);

        jSplitPane1.setLeftComponent(jPanel1);

        rightPanel.setLayout(new java.awt.BorderLayout());

        jToolbar.setLayout(new java.awt.FlowLayout(java.awt.FlowLayout.LEFT));
        jToolbar.add(editButton);
        jToolbar.add(deleteButton);
        jToolbar.add(largerButton);
        jToolbar.add(smallerButton);

        jButton2.setText(AppLocal.getIntString("button.JCalendarPanel.newLocalRepository")); // NOI18N
        jButton2.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                jButton2ActionPerformed(evt);
            }
        });
        jToolbar.add(jButton2);

        jOrderEvent.setText(AppLocal.getIntString("button.JCalendarPanel.Order")); // NOI18N
        jOrderEvent.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                jOrderEventActionPerformed(evt);
            }
        });
        jToolbar.add(jOrderEvent);

        jOrderLineEvent.setText(AppLocal.getIntString("button.JCalendarPanel.OrderProduct")); // NOI18N
        jOrderLineEvent.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                jOrderLineEventActionPerformed(evt);
            }
        });
        jToolbar.add(jOrderLineEvent);

        rightPanel.add(jToolbar, java.awt.BorderLayout.PAGE_START);

        jSplitPane1.setRightComponent(rightPanel);

        add(jSplitPane1, java.awt.BorderLayout.CENTER);

        jMessagePanel.setLayout(new java.awt.BorderLayout());
        jMessagePanel.add(messageArea, java.awt.BorderLayout.CENTER);

        add(jMessagePanel, java.awt.BorderLayout.PAGE_END);
    }// </editor-fold>//GEN-END:initComponents

    private void jButton2ActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jButton2ActionPerformed
        editLocalCalendar ( null );
    }//GEN-LAST:event_jButton2ActionPerformed

    private void jOrderLineEventActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jOrderLineEventActionPerformed

        try {
            JOrderLineFilterDialog orderTypeFiler = JOrderLineFilterDialog.getOrderFilterQBFDialog(this, m_App, dlSales, dlCustomers);
            orderTypeFiler.setVisible(true);
            if (orderTypeFiler.isOK()) {
                OrderLineEventStore orderLineStore=new OrderLineEventStore(this.dlSales,(Object[])orderTypeFiler.createValue());
                dataRepository.addERPCalendar(new ERPCalendar(orderLineStore,"orderLine"));
            }
        } catch (BasicException ex) {
            new MessageInf(ex).show(this);
        }
    }//GEN-LAST:event_jOrderLineEventActionPerformed

    private void jOrderEventActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jOrderEventActionPerformed
        try {
            JOrderFilterQBFDialog orderTypeFiler = JOrderFilterQBFDialog.getOrderFilterQBFDialog(this, m_App, dlSales, dlCustomers);
            orderTypeFiler.setVisible(true);
            if (orderTypeFiler.isOK()) {
                OrderEventStore orderStore=new OrderEventStore(this.dlSales,(Object[])orderTypeFiler.createValue());
                dataRepository.addERPCalendar(new ERPCalendar(orderStore,"order"));
            }
        } catch (BasicException ex) {
             new MessageInf(ex).show(this);
        }
    }//GEN-LAST:event_jOrderEventActionPerformed

    // Variables declaration - do not modify//GEN-BEGIN:variables
    private javax.swing.JButton deleteButton;
    private javax.swing.JButton editButton;
    private javax.swing.JButton jButton2;
    private javax.swing.JPanel jCalendars;
    private javax.swing.JPanel jMessagePanel;
    private javax.swing.JButton jOrderEvent;
    private javax.swing.JButton jOrderLineEvent;
    private javax.swing.JPanel jPanel1;
    private javax.swing.JPanel jPanel3;
    private javax.swing.JSplitPane jSplitPane1;
    private javax.swing.JSplitPane jSplitPane2;
    private javax.swing.JPanel jToolbar;
    private javax.swing.JButton largerButton;
    private javax.swing.JLabel messageArea;
    private javax.swing.JPanel rightPanel;
    private javax.swing.JButton smallerButton;
    // End of variables declaration//GEN-END:variables

    public void paint(Graphics g) {
        if (!this.fontsInitialized) {
            this.fontsInitialized = true;
            Font currentFont = g.getFont();
            Font newFont = new Font(currentFont.getFamily(), currentFont.getStyle(), currentFont.getSize() + prefs.getDisplayFontSize());
            eventViewPanel.setAllFonts(newFont);
            calendarPanel.setFont(newFont);
        }
        super.paint(g);
    }

    public Vector<Calendar> loadCalendars(File dir) {
        Vector<Calendar> ret = new Vector<Calendar>();
        File f = new File(dir, CALENDARS_XML_FILE);
        if (!f.exists()) {
            String name = (String) System.getProperty("user.name");
            if (name == null) {
                name = "Unnamed Calendar";
            }
            Calendar def = new Calendar(dir, name);
            this.showMessage("A new calendar named was created for you" + ": " + name);
            ret.addElement(def);
        } else {
            try {
                ret = Calendar.readCalendars(f);
            } catch (Exception e1) {
                this.fatalError("Error reading calendar file " + f + "\n\n" + "Error" + ":\n" + e1.getMessage());
                e1.printStackTrace();
            }
        }
        return ret;
    }

    public void saveCalendars(File dir) {
        File f = new File(dir, CALENDARS_XML_FILE);
        try {
            Calendar.writeCalendars(f, dataRepository.getCalendars());
        } catch (IOException e1) {
            this.showError("Error writing calendars" + ":\n" + e1.getMessage());
            e1.printStackTrace();
        }
    }

    public void setMessage(String msg) {
        this.messageArea.setText(msg);
    }

    /**
     * Update the toolbar. You can only modify local calendars (for now, at
     * least), so unless an event from a local calendar was selected, the edit and
     * delete buttons should be disabled.
     */
    void updateToolbar() {
        boolean canEdit = false;
        boolean selected = false;
        EventInstance eventInstance = calendarPanel.getSelectedEvent();
        selected = (eventInstance != null);
        if (selected && eventInstance instanceof SingleEvent) {
            SingleEvent se = (SingleEvent) eventInstance;
            canEdit = (se.getCalendar().getType() == Calendar.LOCAL_CALENDAR) || (se.getCalendar().getType() == Calendar.REMOTE_ICAL_CALENDAR && se.getCalendar().getCanWrite());
        }
        editButton.setEnabled(selected && canEdit);
        deleteButton.setEnabled(selected && canEdit);
        smallerButton.setEnabled(prefs.getDisplayFontSize() > -4);
        largerButton.setEnabled(prefs.getDisplayFontSize() < 4);
        // Show text?
        if (prefs.getToolbarIconText()) {
            this.editButton.setText(EDIT_EVENT_LABEL);
            this.deleteButton.setText(DELETE_EVENT_LABEL);
            this.largerButton.setText(LARGER_FONT_LABEL);
            this.smallerButton.setText(SMALLER_FONT_LABEL);
        } else {
            this.editButton.setText(null);
            this.deleteButton.setText(null);
            this.largerButton.setText(null);
            this.smallerButton.setText(null);
        }
    }

    protected JPanel createERPCalendarSelectionPanel(Vector calendars) {
        JPanel topPanel = new JPanel();
        topPanel.setLayout(new BorderLayout());

        this.erpCalendarJList = new JListWithCheckBoxes(new Vector<Object>());
        updateERPCalendarJList();
        this.erpCalendarJList.addListItemChangeListener(new ListItemChangeListener() {

            public void itemSelected(int ind) {
                dataRepository.getERPCalendars().elementAt(ind).setSelected(true);
                handleCalendarFilterSelection();
            }

            public void itemUnselected(int ind) {
                dataRepository.getERPCalendars().elementAt(ind).setSelected(false);
                handleCalendarFilterSelection();
            }

            public Vector<ListItemMenuItem> getMenuChoicesForIndex(int ind) {
                Vector<ListItemMenuItem> ret = new Vector<ListItemMenuItem>();
                ERPCalendar c = dataRepository.getERPCalendars().elementAt(ind);
                ret.addElement(new ListItemMenuItem(MENU_CALENDAR_EDIT)); 
                ret.addElement(new ListItemMenuItem(MENU_CALENDAR_DELETE));
                return ret;
            }

            public void menuChoice(int ind, String actionCommand) {
                ERPCalendar c = dataRepository.getERPCalendars().elementAt(ind);

                if (MENU_CALENDAR_EDIT.equals(actionCommand)) {
                    editERPCalendar(c);
                }else if (MENU_CALENDAR_DELETE.equals(actionCommand)) {
                    if (JOptionPane.showConfirmDialog(parent,
                            "Are you sure you want to\nDelete the following calendar?" + "\n\n" + c.toString(), "Confirm Delete",
                            JOptionPane.YES_NO_OPTION) == 0) {
                        deleteERPCalendar(c);
                    }
                } else {
                    System.err.println("Unknown menu command: " + actionCommand);
                }
            }
        });

        /**
        for (int i = 0; i < calendars.size(); i++) {
            Calendar c = dataRepository.getCalendars().elementAt(i);
            ListItem item = this.calendarJList.getListItemAt(i);
            item.setState(c.isSelected() ? ListItem.STATE_YES : ListItem.STATE_OFF);
        }
       */

        topPanel.add(new MyScrollPane(this.erpCalendarJList), BorderLayout.CENTER);

        return topPanel;
    }

    /**
     * Create the file selection area on the top side of the window. This will
     * include a split pane where the left will allow navigation and selection of
     * dates and the right will allow the selection of a specific entry.
     *
     * @return
     */
    protected JPanel createCalendarSelectionPanel(Vector calendars) {
        JPanel topPanel = new JPanel();
        topPanel.setLayout(new BorderLayout());

        this.calendarJList = new JListWithCheckBoxes(new Vector<Object>());
        updateCalendarJList();
        this.calendarJList.addListItemChangeListener(new ListItemChangeListener() {

            public void itemSelected(int ind) {
                dataRepository.getCalendars().elementAt(ind).setSelected(true);
                handleCalendarFilterSelection();
            }

            public void itemUnselected(int ind) {
                dataRepository.getCalendars().elementAt(ind).setSelected(true);
                handleCalendarFilterSelection();
            }

            public Vector<ListItemMenuItem> getMenuChoicesForIndex(int ind) {
                Vector<ListItemMenuItem> ret = new Vector<ListItemMenuItem>();
                Calendar c = dataRepository.getCalendars().elementAt(ind);
                ret.addElement(new ListItemMenuItem(MENU_CALENDAR_EDIT));
                ret.addElement(new ListItemMenuItem(MENU_CALENDAR_REFRESH, c.getType() != Calendar.LOCAL_CALENDAR));
                ret.addElement(new ListItemMenuItem(MENU_CALENDAR_DELETE));
                ret.addElement(new ListItemMenuItem(MENU_CALENDAR_ADD_EVENT, c.getType() == Calendar.LOCAL_CALENDAR));
                if (c.getType() == Calendar.REMOTE_ICAL_CALENDAR) {
                    // Does this calendar have errors?
                    // TODO: implement error viewer...
                    // Vector<ParseError> errors =
                    // dataRepository.getErrorsAt ( ind );
                    // if ( errors != null && errors.size () > 0 )
                    // ret.addElement ( MENU_CALENDAR_VIEW_ERRORS + " "
                    // + "("
                    // + errors.size () + ")" );
                }
                return ret;
            }

            public void menuChoice(int ind, String actionCommand) {
                Calendar c = dataRepository.getCalendars().elementAt(ind);
                if (MENU_CALENDAR_EDIT.equals(actionCommand)) {
                    editCalendar(c);
                } else if (MENU_CALENDAR_REFRESH.equals(actionCommand)) {
                    if (c.getType() == Calendar.LOCAL_CALENDAR) {
                        showError("You can only refresh\nremote/subscribed calendars.");
                    } else {
                        refreshCalendar(c);
                    }
                } else if (MENU_CALENDAR_DELETE.equals(actionCommand)) {
                    if (JOptionPane.showConfirmDialog(parent,
                            "Are you sure you want to\nDelete the following calendar?" + "\n\n" + c.toString(), "Confirm Delete",
                            JOptionPane.YES_NO_OPTION) == 0) {
                        deleteCalendar(c);
                    }
                } else if (MENU_CALENDAR_ADD_EVENT.equals(actionCommand)) {
                    Date now = Date.getCurrentDateTime("DTSTART");
                    now.setMinute(0);
                    new EditEventWindow(parent, dataRepository, now, c);
                } else {
                    System.err.println("Unknown menu command: " + actionCommand);
                }
            }
        });

        for (int i = 0; i < dataRepository.getCalendars().size(); i++) {
            Calendar c = dataRepository.getCalendars().elementAt(i);
            ListItem item = this.calendarJList.getListItemAt(i);
            item.setState(c.isSelected() ? ListItem.STATE_YES : ListItem.STATE_OFF);
        }

        topPanel.add(new MyScrollPane(this.calendarJList), BorderLayout.CENTER);

        return topPanel;
    }

    protected JPanel createCategorySelectionPanel(Vector categories) {
        JPanel panel = new JPanel();
        panel.setLayout(new BorderLayout());
        this.categoryJList = new JList(categories);
        final JList list = this.categoryJList;
        updateCategoryJList();

        JPanel buttonPanel = new JPanel();
        buttonPanel.setLayout(new FlowLayout());
        JButton allButton = new JButton("Select All");
        allButton.addActionListener(new ActionListener() {

            public void actionPerformed(ActionEvent e) {
                int len = list.getModel().getSize();
                if (len > 0) {
                    list.getSelectionModel().setSelectionInterval(0, len - 1);
                }
            }
        });
        buttonPanel.add(allButton);
        JButton noneButton = new JButton("Clear");
        noneButton.addActionListener(new ActionListener() {

            public void actionPerformed(ActionEvent e) {
                list.clearSelection();
            }
        });
        buttonPanel.add(noneButton);
        panel.add(buttonPanel, BorderLayout.SOUTH);

        // Add handler for when user changes category selectios
        list.addListSelectionListener(new ListSelectionListener() {

            @Override
            public void valueChanged(ListSelectionEvent e) {
                handleCategoryFilterSelection();
            }
        });

        JScrollPane sp = new MyScrollPane(this.categoryJList);
        panel.add(sp, BorderLayout.CENTER);
        return panel;
    }

    // Handle user selecting a category to filter by
    void handleCategoryFilterSelection() {
        boolean uncategorized = this.categoryJList.getSelectionModel().isSelectedIndex(0);
        int[] selected = this.categoryJList.getSelectedIndices();
        Vector selectedCats = new Vector<String>();
        for (int i = 0; i < selected.length; i++) {
            if (selected[i] > 0) {
                String cat = (String) this.categoryJList.getModel().getElementAt(
                        selected[i]);
                selectedCats.addElement(cat);
            }
        }
        if (selected == null || selected.length == 0) {
            ap.setTitleAt(1, "Categories");
            this.dataRepository.clearCategoryFilter();
        } else {
            ap.setTitleAt(1, "Categories" + " [" + selected.length + "]");
            this.dataRepository.setCategoryFilter(uncategorized, selectedCats);
        }
        this.calendarPanel.clearSelection();
        this.dataRepository.rebuild();
        this.calendarPanel.repaint();
    }

    // Handle user selecting a calendar checkbox to display/hide a calendar
    void handleCalendarFilterSelection() {
        // Repaint the calendar view, which will reload the data
        for (int i = 0; i < dataRepository.getCalendars().size(); i++) {
            dataRepository.getCalendars().elementAt(i).setSelected(
                    this.calendarJList.getListItemAt(i).getState() == ListItem.STATE_YES);
        }
        this.calendarPanel.clearSelection();
        this.dataRepository.rebuild();
        this.calendarPanel.repaint();
    }

    public void editCalendar(Calendar c) {
        if (c.getType() == Calendar.LOCAL_CALENDAR) {
            editLocalCalendar(c);
        } else {
            new EditRemoteCalendarWindow(parent, dataRepository, c,
                    getDataDirectory());
        }
    }

    /**
     * Update the list of Calendars shown to the user
     */
    public void updateCategoryJList() {
        // Get current selections so we can preserve
        Object[] oldSelections = this.categoryJList.getSelectedValues();
        HashMap<String, String> old = new HashMap<String, String>();
        for (int i = 0; i < oldSelections.length; i++) {
            old.put(oldSelections[i].toString(), oldSelections[i].toString());
        }
        Vector cats = dataRepository.getCategories();
        // Sort categories alphabetically
        Collections.sort(cats);
        cats.insertElementAt("Uncategorized", 0);
        this.categoryJList.setListData(cats);
        int[] newSelections = new int[oldSelections.length];
        int j = 0;
        for (int i = 0; i < dataRepository.getCategories().size(); i++) {
            String cat = (String) dataRepository.getCategories().elementAt(i);
            if (old.containsKey(cat)) {
                newSelections[j++] = i + 1; // skip over "uncategorized"
            }
        }
        int[] indices = new int[j];
        for (int i = 0; i < j; i++) {
            indices[i] = newSelections[i];
        }
        this.categoryJList.setSelectedIndices(indices);
        this.categoryJList.validate();
    }

    /**
     * Refresh the specified calendar by reloading it from its URL. Because this
     * is likely to take a second or more in ideal circumstances (and much longer
     * in many cases), we will use the SwingWorker class to execute this in a
     * separate thread so we don't lock up the UI.
     *
     * @param cal
     *          The Calendar to refresh
     */
    public void refreshCalendar(final Calendar cal) {
        // Before we get started, update the status bar to indicate we are
        // loading
        // the calendar.
        showStatusMessage("Refreshing calendar" + ": " + cal.getName());

        SwingWorker refreshWorker = new SwingWorker() {

            private String error = null;
            private String statusMsg = null;
            private File outputFile = null;

            public Object construct() {
                // Execute time-consuming task...
                // For now, we only support HTTP/HTTPS since 99.99% of all users
                // will
                // use it
                // instead of something like FTP.
                outputFile = new File(dataDir, cal.getFilename() + ".new");
                String username = null, password = null;
                if (cal.getAuthType() == Calendar.AUTH_BASIC) {
                    username = cal.getAuthUsername();
                    password = cal.getAuthPassword();
                }
                HttpClientStatus result = HttpClient.getRemoteCalendar(cal.getUrl(),
                        username, password, outputFile);
                // We're not supposed to make UI calls from this thread. So,
                // when
                // we get an error, save it in the error variable for use in the
                // finished method.
                // TODO: implement a way to show these errors to the user.
                switch (result.getStatus()) {
                    case HttpClientStatus.HTTP_STATUS_SUCCESS:
                        statusMsg = "Calendar successfully refreshed" + ": " + cal.getName();
                        break;
                    case HttpClientStatus.HTTP_STATUS_AUTH_REQUIRED:
                        error = "Authorization required.\nPlease provide a username\n" + "and password." + "\n\n" + "Calendar" + ": " + cal.getName() + "\n" + "URL" + ": " + cal.getUrl();
                        return null;
                    case HttpClientStatus.HTTP_STATUS_NOT_FOUND:
                        error = "Invalid calendar URL (not found).\n\nServer response" + ": " + result.getMessage();
                        return null;
                    default:
                    case HttpClientStatus.HTTP_STATUS_OTHER_ERROR:
                        error = "Error downloading calendar.\n\nServer response: " + result.getMessage() + "\n\n" + "Calendar" + ": " + cal.getName() + "\n" + "URL" + ": " + cal.getUrl();
                        return null;
                }
                return null;
            }

            public void finished() {
                // Update UI
                if (error != null) {
                    showError(error);
                }
                if (this.statusMsg != null) {
                    showStatusMessage(statusMsg);
                }
                if (error == null) {
                    // TODO: validate what we downloaded was ICS data rather
                    // than an HTML
                    // page
                    // Rename file from ".ics.new" to ".ics"
                    File file = new File(dataDir, cal.getFilename());
                    // Delete old file first since renameTo may file if file
                    // already
                    // exists
                    file.delete();
                    // Now rename
                    if (!outputFile.renameTo(file)) {
                        // Error renaming
                        showError("Error renaming file");
                    } else {
                        // System.out.println ( "Renamed " + outputFile + " to "
                        // + file );
                        // If no error, then save calendar update
                        cal.setLastUpdatedAsNow();
                        saveCalendars(dataDir);
                        dataRepository.updateCalendar(getDataDirectory(), cal);
                    }
                }
            }
        };
        refreshWorker.start();
    }

    private void deleteERPCalendar(ERPCalendar c) {
        boolean found = false;
        for (int i = 0; i < dataRepository.getERPCalendars().size() && !found; i++) {
            ERPCalendar c1 = (ERPCalendar) dataRepository.getERPCalendars().elementAt(i);
            if (c1.equals(c)) {
                dataRepository.removeCalendar(c);
                found = true;
            }
        }
        if (found) {
            updateERPCalendarJList();
            this.calendarPanel.repaint();
        } else {
            System.err.println("deleteCalendar: could not find calendar!");
        }
    }

    public void deleteCalendar(Calendar c) {
        boolean found = false;
        for (int i = 0; i < dataRepository.getCalendars().size() && !found; i++) {
            Calendar c1 = (Calendar) dataRepository.getCalendars().elementAt(i);
            if (c1.equals(c)) {
                dataRepository.removeCalendar(getDataDirectory(), c);
                found = true;
            }
        }
        if (found) {
            updateCalendarJList();
            updateCategoryJList ();
            this.dataRepository.rebuild();
            this.calendarPanel.repaint();
            saveCalendars(getDataDirectory());
        } else {
            System.err.println("deleteCalendar: could not find calendar!");
        }
    }

    /**
     * Update the list of Calendars shown to the user
     */
    public void updateCalendarJList() {
        this.calendarJList.setChoices(dataRepository.getCalendars());
        for (int i = 0; i < dataRepository.getCalendars().size(); i++) {
            Calendar cal = (Calendar) dataRepository.getCalendars().elementAt(i);
            ListItem item = this.calendarJList.getListItemAt(i);
            item.setBackground(cal.getBackgroundColor());
            item.setForeground(cal.getForegroundColor());
            item.setState(cal.isSelected() ? ListItem.STATE_YES
                    : ListItem.STATE_OFF);
        }
        this.calendarJList.validate();
    }

    void showStatusMessage(String string) {
        this.messageArea.setText(string);
    }

    void showMessage(String message) {
        JOptionPane.showMessageDialog(parent, message, "Notice",
                JOptionPane.INFORMATION_MESSAGE);
    }

    void showError(String message) {
        System.err.println("Error" + ": " + message);
        JOptionPane.showMessageDialog(parent, message, "Error",
                JOptionPane.ERROR_MESSAGE);
    }

    void fatalError(String message) {
        System.err.println("Fatal error" + ": " + message);
        JOptionPane.showMessageDialog(parent, message, "Fatal Error",
                JOptionPane.ERROR_MESSAGE);
        System.exit(1);
    }

    protected JButton makeNavigationButton(String imageName,
            String actionCommand, String toolTipText, String altText) {
        JButton button;
        String imgLocation = null;
        URL imageURL = null;

        // Look for the image.
        imgLocation = "images/" + imageName;
        if (imageName != null) {
            imageURL = getResource(imgLocation);
        }

        if (imageURL != null) { // image found
            button = new JButton(altText);
            button.setIcon(new ImageIcon(imageURL, altText));
        } else {
            // no image found
            button = new JButton(altText);
            if (imageName != null) {
                System.err.println("Resource not found" + ": " + imgLocation);
            }
        }

        button.setVerticalTextPosition(JButton.BOTTOM);
        button.setHorizontalTextPosition(JButton.CENTER);
        button.setActionCommand(actionCommand);
        button.setToolTipText(toolTipText);

        // Decrease font size by 2 if we have an icon
        if (imageURL != null) {
            Font f = button.getFont();
            Font newFont = new Font(f.getFamily(), Font.PLAIN, f.getSize() - 2);
            button.setFont(newFont);
        }

        return button;
    }

    private Color getForegroundColorForBackground(Color bg) {
        Color ret = Color.white;
        if (bg.getRed() > 128 && bg.getGreen() > 128 && bg.getRed() > 128) {
            ret = Color.black;
        }
        return ret;
    }

      protected void editERPCalendar(final ERPCalendar c) {
        final JDialog addLocal = new JDialog(this.parent);
        addLocal.setLocationRelativeTo(null);
        final JTextField nameField = new JTextField(30);
        final ColorButton colorField = new ColorButton();
        int[] props = {1, 2};

        if (c != null) {
            nameField.setText(c.getName());
        }

        addLocal.setTitle(c != null ? "Edit ERP Calendar"
                : "Add ERP Calendar");
        addLocal.setModal(true);
        Container content = addLocal.getContentPane();
        content.setLayout(new BorderLayout());
        JPanel buttonPanel = new JPanel();
        buttonPanel.setLayout(new FlowLayout());
        JButton cancel = new JButton(CalendarLocal.getIntString("Button.Cancel"));
        cancel.addActionListener(new ActionListener() {

            public void actionPerformed(ActionEvent event) {
                addLocal.dispose();
            }
        });
        buttonPanel.add(cancel);
        JButton ok = new JButton(c == null ? CalendarLocal.getIntString("Buttom.Add") : CalendarLocal.getIntString("Button.Save"));
        ok.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent event) {
                    String name = nameField.getText();
                    if (name == null || name.trim().length() == 0) {
                        showError("You must provide a calendar name");
                        return;
                    }
                    Color color = colorField.getSelectedColor();
                    c.setBackgroundColor(color);
                    c.setBorderColor(getForegroundColorForBackground(color));
                    c.setForegroundColor(getForegroundColorForBackground(color));
                      // updating calendar...
                    dataRepository.updateCalendar(c);
                    updateERPCalendarJList();
                    calendarPanel.repaint();
                    showStatusMessage("Updated ERP calendar" + ": " + name);
                addLocal.dispose();
            }
        });
        buttonPanel.add(ok);
        content.add(buttonPanel, BorderLayout.SOUTH);

        JPanel main = new JPanel();
        main.setBorder(BorderFactory.createTitledBorder(c == null ? "New ERP Calendar"
                : "Edit ERP Calendar"));
        main.setLayout(new GridLayout(2, 1));
        JPanel namePanel = new JPanel();
        namePanel.setLayout(new ProportionalLayout(props,
                ProportionalLayout.HORIZONTAL_LAYOUT));
        namePanel.add(new JLabel("Calendar Name" + ": "));
        namePanel.add(nameField);
        main.add(namePanel);

        JPanel colorPanel = new JPanel();
        colorPanel.setLayout(new ProportionalLayout(props,
                ProportionalLayout.HORIZONTAL_LAYOUT));
        colorPanel.add(new JLabel("Background Color" + ": "));
        JPanel colorSub = new JPanel();
        colorSub.setLayout(new BorderLayout());
        colorField.setSelectedColor(c == null ? Color.blue : c.getBackgroundColor());
        colorSub.add(colorField, BorderLayout.WEST);
        colorPanel.add(colorSub);
        main.add(colorPanel);

        content.add(main, BorderLayout.CENTER);

        addLocal.pack();
        addLocal.setVisible(true);

      }

    protected void editLocalCalendar(final Calendar c) {
        final JDialog addLocal = new JDialog(this.parent);
        addLocal.setLocationRelativeTo(null);
        final JTextField nameField = new JTextField(30);
        final ColorButton colorField = new ColorButton();
        int[] props = {1, 2};

        if (c != null) {
            nameField.setText(c.getName());
        }

        addLocal.setTitle(c != null ? CalendarLocal.getIntString("Title.LocalCalendar.Edit")
                : CalendarLocal.getIntString("Title.LocalCalendar.Add"));
        addLocal.setModal(true);
        Container content = addLocal.getContentPane();
        content.setLayout(new BorderLayout());
        JPanel buttonPanel = new JPanel();
        buttonPanel.setLayout(new FlowLayout());
        JButton cancel = new JButton(CalendarLocal.getIntString("Button.Cancel"));
        cancel.addActionListener(new ActionListener() {

            public void actionPerformed(ActionEvent event) {
                addLocal.dispose();
            }
        });
        buttonPanel.add(cancel);
        JButton ok = new JButton(c == null ? CalendarLocal.getIntString("Buttom.Add") : CalendarLocal.getIntString("Button.Save"));
        ok.addActionListener(new ActionListener() {

            @Override
            public void actionPerformed(ActionEvent event) {
                try {
                    String name = nameField.getText();
                    if (name == null || name.trim().length() == 0) {
                        showError("You must provide a calendar name");
                        return;
                    }
                    Color color = colorField.getSelectedColor();
                    showStatusMessage("Creating calendar...");
                    Calendar cal = null;
                    if (c == null) {
                        cal = new Calendar(getDataDirectory(), name);
                    } else {
                        cal = c;
                    }
                    cal.setBackgroundColor(color);
                    cal.setBorderColor(getForegroundColorForBackground(color));
                    cal.setForegroundColor(getForegroundColorForBackground(color));
                    cal.setLastUpdatedAsNow();
                    File file = new File(getDataDirectory(), cal.getFilename());
                    if (c == null) {
                        // Create empty iCalendar file
                        FileWriter writer = new FileWriter(file);
                        ICalendarParser icalParser = new ICalendarParser(
                                ICalendarParser.PARSE_STRICT);
                        icalParser.toICalendar();
                        writer.write(icalParser.toICalendar());
                        writer.close();
                    }
                    if (c == null) {
                        showStatusMessage("New local calendar added" + ": " + name);
                        dataRepository.addCalendar(getDataDirectory(), cal, false);
                        // This will call us back with calendarAdded (below)
                    } else {
                        // updating calendar...
                        dataRepository.updateCalendar(getDataDirectory(), cal);
                        showStatusMessage("Updated local calendar" + ": " + name);
                    }
                    // System.out.println ( "Created cal file: " + file );
                } catch (Exception e1) {
                    showError("Error writing calendar" + ": " + e1.getMessage());
                    return;
                }
                addLocal.dispose();
            }
        });
        buttonPanel.add(ok);
        content.add(buttonPanel, BorderLayout.SOUTH);

        JPanel main = new JPanel();
        main.setBorder(BorderFactory.createTitledBorder(c == null ? CalendarLocal.getIntString("Title.LocalCalendar.Add")
                : CalendarLocal.getIntString("Title.LocalCalendar.Edit")));
        main.setLayout(new GridLayout(2, 1));
        JPanel namePanel = new JPanel();
        namePanel.setLayout(new ProportionalLayout(props,
                ProportionalLayout.HORIZONTAL_LAYOUT));
        namePanel.add(new JLabel (CalendarLocal.getIntString("Label.CalendarName") + ": "));
        namePanel.add(nameField);
        main.add(namePanel);

        JPanel colorPanel = new JPanel();
        colorPanel.setLayout(new ProportionalLayout(props,
                ProportionalLayout.HORIZONTAL_LAYOUT));
        colorPanel.add(new JLabel( CalendarLocal.getIntString("Label.BackgroundColor") + ": "));
        JPanel colorSub = new JPanel();
        colorSub.setLayout(new BorderLayout());
        colorField.setSelectedColor(c == null ? Color.blue : c.getBackgroundColor());
        colorSub.add(colorField, BorderLayout.WEST);
        colorPanel.add(colorSub);
        main.add(colorPanel);

        content.add(main, BorderLayout.CENTER);

        addLocal.pack();
        addLocal.setVisible(true);
    }

    public void eventAdded(Event event) {
        this.updateCategoryJList ();
        handleCalendarFilterSelection();
        this.eventViewPanel.clear();
    }

    public void eventUpdated(Event event) {
        this.updateCategoryJList ();
        handleCalendarFilterSelection();
        this.eventViewPanel.clear();
    }

    public void eventDeleted(Event event) {
        this.updateCategoryJList ();
        handleCalendarFilterSelection();
        this.eventViewPanel.clear();
    }

    public void eventSelected(EventInstance eventInstance) {
        if (eventInstance instanceof SingleEvent) {
            SingleEvent se = (SingleEvent) eventInstance;
            Date eventDate = null;
            try {
                eventDate = new Date("DTSTART", eventInstance.getYear(), eventInstance.getMonth(), eventInstance.getDayOfMonth());
            } catch (BogusDataException e1) {
                e1.printStackTrace();
                return;
            }
            if (eventInstance.hasTime()) {
                eventDate.setDateOnly(false);
                eventDate.setHour(eventInstance.getHour());
                eventDate.setMinute(eventInstance.getMinute());
                eventDate.setSecond(eventInstance.getSecond());
            } else {
                eventDate.setDateOnly(true);
            }
            updateToolbar();
            this.eventViewPanel.update(eventDate, se.getEvent(), se.getCalendar());
            // Select the calendar on the left that the selected event belongs to.
            if (se.getCalendar() != null) {
                int ind = -1;
                for (int i = 0; i < this.dataRepository.getCalendars().size() && ind < 0; i++) {
                    Calendar c = this.dataRepository.getCalendars().elementAt(i);
                    if (c.equals(se.getCalendar())) {
                        ind = i;
                    }
                }
                if (ind >= 0) {
                    this.calendarJList.setSelectedIndex(ind);
                }
            }
        }
    }

    public void calendarAdded(Object c) {
        updateCalendarJList();
        updateCategoryJList ();
        updateERPCalendarJList();
        if(c instanceof Calendar){
           saveCalendars(getDataDirectory());
           this.dataRepository.rebuild();
        }
        this.calendarPanel.repaint();
    }

    public void calendarUpdated(Object c) {
        updateCalendarJList();
        updateCategoryJList ();
        updateERPCalendarJList();
       if(c instanceof Calendar){
           saveCalendars(getDataDirectory());
           this.dataRepository.rebuild();
        }
        this.calendarPanel.repaint();
    }

    public void calendarDeleted(Object c) {
        updateCalendarJList();
        updateCategoryJList ();
        updateERPCalendarJList();
        if(c instanceof Calendar){
           saveCalendars(getDataDirectory());
           this.dataRepository.rebuild();
        }
        this.calendarPanel.repaint();
    }

    public void displaySettingsChanged() {
        this.calendarPanel.setShowTime(prefs.getDisplayHourInMonthView());
        Font oldFont = this.calendarPanel.getFont();
        Font defaultFont = this.getFont();
        Font newFont = new Font(oldFont.getFamily(), oldFont.getStyle(),
                defaultFont.getSize() + prefs.getDisplayFontSize());
        this.calendarPanel.setFont(newFont);
        this.dataRepository.rebuild();
        this.calendarPanel.repaint();
        this.eventViewPanel.setAllFonts(newFont);
        updateToolbar();
    }

    public void eventDoubleClicked(EventInstance eventInstance) {
        if (eventInstance != null&&eventInstance instanceof SingleEvent) {
            SingleEvent se = (SingleEvent) eventInstance;
            boolean canEdit = (se.getCalendar().getType() == Calendar.LOCAL_CALENDAR) || (se.getCalendar().getType() == Calendar.REMOTE_ICAL_CALENDAR && se.getCalendar().getCanWrite());
            if (!canEdit) {
                showError("You cannot edit events\non the following calendar" + ": " + "\n\n" + se.getCalendar().getName());
            } else {
                new EditEventWindow(parent, dataRepository, se.getEvent(), se.getCalendar());
            }
        }
    }

    public void dateDoubleClicked(int year, int month, int dayOfMonth) {
        try {
            Date d = new Date("DTSTART", year, month, dayOfMonth);
            new EditEventWindow(parent, dataRepository, d, null);
        } catch (BogusDataException e1) {
            e1.printStackTrace();
        }
    }

    public void eventUnselected() {
        updateToolbar();
        this.eventViewPanel.clear();
    }

    URL getResource(String name) {
        return this.getClass().getClassLoader().getResource(name);
    }

    /**
     * Get the data directory that data files for this application will be stored
     * in.
     *
     * @return
     */
    // TODO: allow user preferences to override this setting
    File getDataDirectory() {
        if (dataDir != null) {
            return dataDir;
        }
        String s = (String) System.getProperty("user.home");
        if (s == null) {
            System.err.println("Could not find user.home setting. Using current directory instead.");
            s = ".";
        }
        File f = new File(s);
        if (f == null) {
            fatalError("Invalid user.home value" + ": " + s);
        }
        if (!f.exists()) {
            fatalError("Home directory does not exist" + ": " + f);
        }
        if (!f.isDirectory()) {
            fatalError("Home directory is not a directory: " + f);
        }
        // Use the home directory as the base. Data files will
        // be stored in a subdirectory.
        File dir = new File(f, DEFAULT_DIR_NAME);
        if (!dir.exists()) {
            if (!dir.mkdirs()) {
                fatalError("Unable to create data directory" + ": " + dir);
            }
            showMessage("The following directory was created\nto store data files" + ":\n\n" + dir);
        }
        if (!dir.isDirectory()) {
            fatalError("Not a directory: " + dir);
        }
        dataDir = dir;
        return dir;
    }

    @Override
    public String getTitle() {
        return "";
    }

    @Override
    public void activate() throws BasicException {
    }

    @Override
    public boolean deactivate() {
        return true;
    }

    @Override
    public JComponent getComponent() {
        return this;
    }

    @Override
    public Object getBean() {
        return this;
    }

    private void updateERPCalendarJList() {
       erpCalendarJList.setChoices(dataRepository.getERPCalendars());
        for (int i = 0; i < dataRepository.getERPCalendars().size(); i++) {
            ERPCalendar cal = (ERPCalendar) dataRepository.getERPCalendars().elementAt(i);
            ListItem item = erpCalendarJList.getListItemAt(i);
            item.setBackground(cal.getBackgroundColor());
            item.setForeground(cal.getForegroundColor());
            item.setState(cal.isSelected() ? ListItem.STATE_YES
                    : ListItem.STATE_OFF);
        }
        erpCalendarJList.validate();
    }

	@Override
	public String getModelName() {
		return ERP_UI_Swing_Model.MODEL_NAME;
	}

	@Override
	public void setModel(ERP_UI_Swing_Model mode) {
		 dlSystem = mode.getDLSystem();
	     dlSales = mode.getDLERP();
	     dlCustomers = mode.getDLCustomer();
		
	}
}
